﻿// ----------------------------------------------------------------------------
//  Copyright (C) 成都联宇创新科技有限公司 版权所有。 
//      
//  文件名：NHibernateModule.cs
//  文件功能描述：
//  创建标识：骆智慧 2016/03/04 01:01
//     
//  修改标识：骆智慧  2016/03/10/06:27
//  修改描述：
//  ----------------------------------------------------------------------------

#region 导入名称空间

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using Autofac;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using LightWork.DataAccess;
using NHibernate;
using NHibernate.Bytecode;
using NHibernate.Cache;
using NHibernate.Cfg;
using NHibernate.Context;
using NHibernate.Type;
using Module = Autofac.Module;

#endregion

namespace LightWork.Modules
{
    public class NHibernateModule : Module
    {
        private static string _connectionString;
        private static readonly ISet<Assembly> _assembliesSet = new HashSet<Assembly>();
        private static string _dbType;
        private static bool _debug;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbtype">数据库类型 Oracle、MySql、Postgres、SqlServer</param>
        /// <param name="connectionString"></param>
        /// ///
        /// <param name="debug">调试开发模式</param>
        /// <param name="mapping"></param>
        public NHibernateModule(string dbtype, string connectionString, bool debug, IEnumerable<string> mapping)
        {
            _dbType = dbtype;
            _connectionString = connectionString;
            _debug = debug;
            foreach (var assemblyName in mapping)
            {
                var assembly = Assembly.Load(assemblyName);

                if (_assembliesSet.Contains(assembly))
                {
                    continue;
                }

                _assembliesSet.Add(assembly);
            }
        }

        /// <summary>
        /// 构建NHibernate配置前预处理
        /// </summary>
        /// <param name="connStrBuilder"></param>
        /// <returns></returns>
        private static IPersistenceConfigurer PrepareBuildNHibernateConfiguration(
            Action<ConnectionStringBuilder> connStrBuilder)
        {
            var dbType = _dbType.ToUpper();

            switch (dbType)
            {
                case "ORACLEMGR":
                    return OracleManagedDataClientConfiguration
                        .Oracle10
                        .ConnectionString(connStrBuilder);
                case "ORACLE":
                    return OracleDataClientConfiguration
                        .Oracle10
                        .ConnectionString(connStrBuilder);

                case "MYSQL":
                    return MySQLConfiguration
                        .Standard
                        .ConnectionString(connStrBuilder);

                case "POSTGRES":
                    return PostgreSQLConfiguration
                        .Standard
                        .ConnectionString(connStrBuilder);
                case "SQLSERVER":
                    return MsSqlConfiguration
                        .MsSql2012
                        .ConnectionString(connStrBuilder);
                default:
                    throw new NotImplementedException($"不支持的数据库类型{dbType}");
            }
        }

        /// <summary>
        /// 构建NHibernate配置
        /// </summary>
        /// <returns></returns>
        public Configuration BuildNHibernateConfiguration()
        {
            var nhConfig = Fluently.Configure()
                .ExposeConfiguration(config =>
                {
                    var isDebug = _debug.ToString().ToLower();
                    config.SetProperty("show_sql", isDebug);
                    config.SetProperty("format_sql", isDebug);
                    //config.SetProperty("hibernate.use_sql_comments", isDebug);
                    //config.SetProperty("max_fetch_depth", "2");
                })
                .Database(PrepareBuildNHibernateConfiguration(c => c.Is(_connectionString)))
                .CollectionTypeFactory<DefaultCollectionTypeFactory>()
                .ProxyFactoryFactory<DefaultProxyFactoryFactory>()
                .LoadCurrentSessionContext()
                .EnableNHibernateCache()
                .Mappings(mapping => mapping.LoadAssembly(_assembliesSet))
                .BuildConfiguration();

            return nhConfig;
        }


        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterInstance(this).As<NHibernateModule>().SingleInstance();
            builder.Register(x => x.Resolve<NHibernateModule>().BuildNHibernateConfiguration())
                .As<Configuration>()
                .SingleInstance()
                .InstancePerLifetimeScope();
            builder.Register(x => x.Resolve<Configuration>().BuildSessionFactory())
                .As<ISessionFactory>().SingleInstance();
            builder.Register(x => x.Resolve<ISessionFactory>().OpenSession())
                .As<ISession>().InstancePerLifetimeScope();
            builder.Register(x => new NHibernateUnitOfWork(x.Resolve<ISessionFactory>()))
                .As<IUnitOfWork>();
        }
    }

    #region FluentNHibernate Configuration 扩展方法

    internal static class NHibernateConfigExtends
    {
        public static void LoadAssembly(this MappingConfiguration mappings, IEnumerable<Assembly> assemblies)
        {
            foreach (var assembly in assemblies)
            {
                mappings.FluentMappings.AddFromAssembly(assembly);
            }
        }

        /// <summary>
        /// 设置NHibernate Session上下文策略
        /// </summary>
        /// <param name="fluentConfiguration"></param>
        /// <returns></returns>
        public static FluentConfiguration LoadCurrentSessionContext(this FluentConfiguration fluentConfiguration)
        {
            if (HttpContext.Current == null)
            {
                fluentConfiguration.CurrentSessionContext<ThreadStaticSessionContext>();
            }
            else
            {
                fluentConfiguration.CurrentSessionContext<WebSessionContext>();
            }

            return fluentConfiguration;
        }

        /// <summary>
        /// 启用NHibernate缓存
        /// </summary>
        /// <param name="fluentConfiguration"></param>
        /// <returns></returns>
        public static FluentConfiguration EnableNHibernateCache(this FluentConfiguration fluentConfiguration)
        {
            fluentConfiguration.Cache(cacheBuilder =>
            {
                cacheBuilder.ProviderClass<HashtableCacheProvider>();
                cacheBuilder.UseQueryCache();
                //cacheBuilder.UseSecondLevelCache();
                cacheBuilder.QueryCacheFactory<StandardQueryCacheFactory>();
                cacheBuilder.UseMinimalPuts();
            });
            return fluentConfiguration;
        }
    }

    #endregion
}